package com.yss.config;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.exception.CompileExpressionErrorException;
import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
import com.yss.adapter.IAdapter;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
@ConfigurationProperties(prefix = "router-server.router-config")
public class RouterConfig {

    @Setter
    private List<Map<String, LinkedList<String>>> rules;
    private AviatorEvaluatorInstance aviatorInstance;
    @Getter
    private Map<String, List<IAdapter>> ruleAdaptersMapper;

    public RouterConfig() {
        aviatorInstance = AviatorEvaluator.getInstance();
        ruleAdaptersMapper = new LinkedHashMap<>();
    }

    @PostConstruct
    public void init() {
        if (CollectionUtils.isEmpty(rules)) return;
        checkScript();
        loadAdapter();
    }

    private void checkScript() {
        rules.forEach(item -> {
            try {
                aviatorInstance.validate(item.get("rule").get(0));
            } catch (ExpressionSyntaxErrorException | CompileExpressionErrorException exp) {
                throw exp;
            }
        });
    }

    private void loadAdapter() {
        rules.forEach(mapperItem -> {
            String rule = mapperItem.get("rule").get(0);
            List<String> adapterClasses = mapperItem.get("adapterClass");

            List<IAdapter> adapters = adapterClasses.stream().map(adapterClassStr -> {
                IAdapter iAdapter;
                try {
                    Class<IAdapter> aClass = (Class<IAdapter>) Class.forName(adapterClassStr, true, this.getClass().getClassLoader());
                    iAdapter = aClass.newInstance();
                } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                    throw new RuntimeException(
                            String.format("\nRouterConfig adapter class not found, %s", adapterClassStr)
                    );
                }
                return iAdapter;
            }).collect(Collectors.toList());

            ruleAdaptersMapper.put(rule, adapters);
        });
    }
}
